package math

import (
	"hi-jvm/instructions/base"
	"hi-jvm/rtda"
)

/*
位移指令： 分为左移和右移。
右移指令又分为算术右移（有符号右移）和逻辑右移（无符号右移）， 它们的区别在于符号位的扩展
 */

// Shift left int
type ISHL struct{ base.NoOperandsInstruction }


// Arithmetic shift right int
type ISHR struct{ base.NoOperandsInstruction }

// Logical shift right int
type IUSHR struct{ base.NoOperandsInstruction }

// Shift left long
type LSHL struct{ base.NoOperandsInstruction }

// Arithmetic shift right long
type LSHR struct{ base.NoOperandsInstruction }

// Logical shift right long
type LUSHR struct{ base.NoOperandsInstruction }

// 从栈中弹出两个int值
// v1是要位移的变量
// v2是要位移的变量： 注意： <32， 所以使用&0x1f
// GO语言位移操作符右侧必须是无符号整数，所以对v2进行类型转换
// 注意： 先取v2再取v1
func (self *ISHL) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack
	s := getShParam(stack, 0x1f)
	v1 := stack.PopInt()
	result := v1 << s
	stack.PushInt(result)
}

func (self *ISHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack
	s := getShParam(stack, 0x1f)
	v1 := stack.PopInt()
	result := v1 >> s
	stack.PushInt(result)
}

func (self *IUSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack
	s := getShParam(stack, 0x1f)
	v1 := stack.PopInt()
	result := int32(uint32(v1) >> s)
	stack.PushInt(result)
}

func (self *LSHL) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack
	s := getShParam(stack, 0x3f)
	v1 := stack.PopLong()
	result := v1 << s
	stack.PushLong(result)
}

func (self *LSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := uint32(v2) & 0x3f
	result := v1 >> s
	stack.PushLong(result)
}

func (self *LUSHR) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack
	s := getShParam(stack, 0x3f)
	v1 := stack.PopLong()
	result := int64(uint64(v1) >> s)
	stack.PushLong(result)
}

func getShParam(stack *rtda.OperandStack, max uint32) uint32 {
	v := stack.PopInt()
	s := uint32(v) & max
	return s
}